
package de.uni.wuppertal.server.http;

import java.io.*;
import java.util.HashMap;
import java.util.LinkedList;

import de.uni.wuppertal.server.OutputLogEntry;
import de.uni.wuppertal.server.ui.MainWindow;

/**
 * @author Martin Schröder
 * @author Patrik Nordsiek
 */
public class HTTPResponse extends HTTPHeaders
{
	protected OutputStream outputStream;
	protected int code = CODE_OK;
	protected byte[] body;
	protected File file;
	
	public static final int CODE_OK = 200;
	public static final int CODE_NOT_MODIFIED = 304;
	public static final int CODE_NOT_FOUND = 404;
	public static final int CODE_INTERNAL_SERVER_ERROR = 500;
	
	public static HashMap<Integer, String> messages;
	
	static
	{
		messages = new HashMap<Integer, String>();
		
		messages.put(CODE_OK, "OK");
		messages.put(CODE_NOT_MODIFIED, "Not Modified");
		messages.put(CODE_NOT_FOUND, "Not Found");
		messages.put(CODE_INTERNAL_SERVER_ERROR, "Internal Server Error");
	}
	
	public HTTPResponse(OutputStream outputStream)
	{
		this.outputStream = outputStream;
	}
	
	public static String getMessage(int code)
	{
		return messages.get(code);
	}
	
	public int getCode()
	{
		return code;
	}
	
	public HTTPResponse setCode(int code)
	{
		this.code = code;
		
		return this;
	}
	
	public byte[] getBody()
	{
		return body;
	}
	
	public HTTPResponse setBody(byte[] body)
	{
		this.body = body;
		
		return this;
	}
	
	public HTTPResponse setBody(File f)
	{
		file = f;
		
		return this;
	}
	
	public void send()
	{
		if(code == CODE_NOT_MODIFIED)
		{
			try
			{
				BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream));
				String m;
				
				MainWindow.getInstance().log(new OutputLogEntry("HTTP - 304 Not Modified"));
				
				writer.write("HTTP/1.1 " + code);
				
				if((m = getMessage(code)) != null)
				{
					writer.write(" " + m);
				}
				
				writer.write(HTTPServer.CRLF);
				writer.write(HTTPServer.CRLF);
				
				writer.close();
				
				return;
			}
			catch(Throwable e)
			{
				throw new HTTPServerException(e.getMessage());
			}
		}
		
		if(file != null)
		{
			setHeader("Content-Length", "" + file.length());
		}
		else if(body == null)
		{
			setHeader("Content-Length", "0");
		}
		else
		{
			setHeader("Content-Length", "" + body.length);
		}
		
		try
		{
			BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream, "US-ASCII"));
			String m;
			String status = "HTTP - " + code;
			
			writer.write("HTTP/1.1 " + code);
			
			if((m = getMessage(code)) != null)
			{
				writer.write(" " + m);
				
				status += " " + m;
			}
			
			MainWindow.getInstance().log(new OutputLogEntry(status));
			
			writer.write(HTTPServer.CRLF);
			
			for(String key : headers.keySet())
			{
				LinkedList<String> h = headers.get(key);
				
				for(String value : h)
				{
					writer.write(key + ": " + value + HTTPServer.CRLF);
				}
			}
			
			writer.write(HTTPServer.CRLF);
			writer.flush();
			
			if(body != null)
			{
				outputStream.write(body);
				outputStream.flush();
			}
			else if(file != null)
			{
				FileInputStream in = new FileInputStream(file);
				
				byte[] buffer = new byte[4096];
				int len = 0;
				
				while((len = in.read(buffer)) != -1)
				{
					outputStream.write(buffer, 0, len);
					outputStream.flush();
				}
				
				in.close();
			}
		}
		catch(Throwable e)
		{
			throw new HTTPServerException(e.getMessage());
		}
	}
}
